package com.xujiang.myblog.network.okhttp;

import android.util.Log;
import android.util.LongSparseArray;

import com.xujiang.myblog.entity.CommonPlus;
import com.xujiang.myblog.tools.FileUtils;
import com.xujiang.myblog.util.L;

import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;

/**
 * Created by xujiang on 2017/4/14.
 */

public class OkHttp3Utils {
    private final String TAG = OkHttp3Utils.class.getSimpleName();
    public final MediaType JSON = MediaType.parse("application/json; charset=utf-8");  //上传格式
    private OkHttpClient mClient;
    private ErrorHandleListener mErrorHandleListener;
    private List<HeaderPlusListener> mHeaderPlus;  //拦截列表
    private Map<String, String> mHeaders;  //添加的请求头列表


    private static OkHttp3Utils INSTANCE;  //此函数对象

    public static OkHttp3Utils get() {  //获得此工具类对象
        if (INSTANCE == null) {
            synchronized (OkHttp3Utils.class) {  //synchronized，Java语言的关键字，可用来给对象和方法或者代码块加锁，当它锁定一个方法或者一个代码块的时候，同一时刻最多只有一个线程执行这个段代码
                if (INSTANCE == null) {
                    INSTANCE = init().build();  //由init加build创建对象
                }
            }
        }
        return INSTANCE;
    }

    //init函数
    public static Init init() {
        return new Init();
    }

    public static OkHttp3Utils setInit(OkHttp3Utils okHttpUtils) {
        return INSTANCE = okHttpUtils;
    }


    public static class Init{
        private final int DEFAULT_HTTP_DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB;
        private OkHttpClient.Builder builder;
        private List<HeaderPlusListener> headerPlus;    //HeaderPlusListener为拦截器接口
        private Map<String, String> headers;
        private Cache cache;

        public Init setDefaultCache() {
            return setDefaultCache(0);  //默认情况下cache为空
        }

        public Init setDefaultCache(long httpDiskCacheSize) {  //设置缓存大小
            try {
                cache = getDefaultCache(httpDiskCacheSize);
            } catch (Exception ignored) {
            }
            return this;
        }


        public Cache getDefaultCache(long httpDiskCacheSize) throws Exception {  //获取cache对象
            File cacheFile = FileUtils.createCacheSDAndroidDirectory(CommonPlus.HTTP_CACHE_DIR); //cache目录  获取的应用程序内部的目录
            if (httpDiskCacheSize == 0) {
                httpDiskCacheSize = DEFAULT_HTTP_DISK_CACHE_SIZE;
            }
            return new Cache(cacheFile, httpDiskCacheSize);
        }

        public void initialization() {    //以下面build构造函数
            OkHttp3Utils.setInit(build());
        }

        private ErrorHandleListener errorHandleListener;

        public OkHttp3Utils build(){
            if(builder == null){
                builder = new OkHttpClient.Builder();  //创建OkHttpClient.Builder
            }
            if(headerPlus == null){
                headerPlus = new LinkedList<>();  //创建拦截器
            }
            if (headers == null) {
                headers = new LinkedHashMap<>();  //
            }
            if (cache != null) {
                builder.cache(cache);  //设置缓存
            }
            if (errorHandleListener==null){
                errorHandleListener = getDefaultErrorHandleListener();  //注册错误拦截
            }
            return new OkHttp3Utils(builder, errorHandleListener, headerPlus, headers);
        }

        //上面为默认

        public OkHttp3Utils build(OkHttpClient.Builder builder) {
            return new OkHttp3Utils(builder);
        }

        public OkHttpClient.Builder getBuilder() {
            return builder;
        }

        public Init setBuilder(OkHttpClient.Builder builder) {
            this.builder = builder;
            return this;
        }



        public Map<String, String> getHeaders() {
            return headers;
        }

        public Init setHeaders(Map<String, String> headers) {
            this.headers = new LinkedHashMap<>(headers);
            return this;
        }

        public Init addHeaders(String key, String value) {
            if (this.headers == null) {
                this.headers = new LinkedHashMap<>();
            }
            this.headers.put(key, value);
            return this;
        }

        public List<HeaderPlusListener> getHeaderPlus() {
            return headerPlus;
        }

        public Init setHeaderPlus(List<HeaderPlusListener> headerPlus) {
            this.headerPlus = new LinkedList<>(headerPlus);
            return this;
        }

        public Init addHeaderPlus(HeaderPlusListener... headerPlus) {
            this.headerPlus = new LinkedList<>(Arrays.asList(headerPlus));
            return this;
        }

        public Cache getCache() {
            return cache;
        }

        public Init setCache(Cache cache) {
            this.cache = cache;
            return this;
        }

        public ErrorHandleListener getErrorHandleListener() {
            return errorHandleListener;
        }

        public Init setErrorHandleListener(ErrorHandleListener errorHandleListener) {
            this.errorHandleListener = errorHandleListener;
            return this;
        }

    }


    private static ErrorHandleListener getDefaultErrorHandleListener(){  //错误拦截器，对response进行拦截
        return new ErrorHandleListener() {
            @Override
            public Response checkError(Response response) throws Exception {
                if(!response.isSuccessful()){
                    String string = "code : " + response.code();
                    if(response.body().contentLength() > 0){
                        try {
                            string = response.body().string();
                        } catch (IOException ignored) {
                        }
                    }
                    throw new Exception(response.message()+":::"+string);
                }
                return response;
            }
        };
    }

    private OkHttp3Utils(OkHttpClient.Builder builder, ErrorHandleListener errorHandleListener,
                         List<HeaderPlusListener> headerPluses, Map<String, String> headers) {
        builder.interceptors().add(new HeaderPlusInterceptor());  //okhttp添加拦截器
        builder.interceptors().add(new ErrorInterceptor());  //okhttp添加拦截器
        builder.interceptors().add(new LogInterceptor(TAG));  //日志拦截器

        //将内部值附值到外部
        this.mClient = builder.build();   //okhttp的client对象
        this.mErrorHandleListener = errorHandleListener;  //错误监听
        this.mHeaderPlus = headerPluses;
        this.mHeaders = headers;
    }


    private OkHttp3Utils(OkHttpClient.Builder builder) {
        this.mClient = builder.build();
        this.mErrorHandleListener = OkHttp3Utils.get().getErrorHandleListener();
        this.mHeaderPlus = OkHttp3Utils.get().getHeaderPlus();
        this.mHeaders = OkHttp3Utils.get().getHeaders();
    }

    public ErrorHandleListener getErrorHandleListener() {
        return mErrorHandleListener;
    }

//请求前的拦截
    private class HeaderPlusInterceptor implements Interceptor{

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request.Builder builder = chain.request().newBuilder();
            Request request = chain.request();
            Map<String,Object> map = new HashMap<>();

//            if(request.body() != null){
//                L.i(TAG,request.body().toString());
//            }

            if(!getHeaderPlus().isEmpty()){  //判空
                for(HeaderPlusListener mHeaderPlu:getHeaderPlus())
                {
                    builder = mHeaderPlu.headerInterceptor(request,builder,map);  //注册
                }
            }
            if(!getHeaders().isEmpty()){
                for(Map.Entry<String,String> entry:getHeaders().entrySet()){   //headers
                    builder.addHeader(entry.getKey(), entry.getValue());  //添加头
                    L.d(TAG, "add header: "+entry.getKey()+":"+entry.getValue());
                }
            }

            return chain.proceed(builder.build()); //返回response
        }
    }

    //返回头部拦截器列表
    public List<HeaderPlusListener> getHeaderPlus(){
        if (mHeaderPlus == null) {
            throw new IllegalStateException("Not Initialize");
        }
        return mHeaderPlus;
    }
    //返回headers
    public Map<String, String> getHeaders() {
        if (mHeaders == null) {
            throw new IllegalStateException("Not Initialize");
        }
        return mHeaders;
    }

//检查错误
    private class ErrorInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            if (mErrorHandleListener != null) {
                try {
                    return mErrorHandleListener.checkError(response);  //注册
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                return response;
            }
            return response;
        }
    }


    public static class LogInterceptor implements Interceptor {

        private static final String TAG = LogInterceptor.class.getSimpleName();

        private String tag = TAG;

        public LogInterceptor(){
            tag = LogInterceptor.class.getSimpleName();
        }

        public LogInterceptor(String tag){
            this.tag = tag;
        }
        //检查是否是存文本
        private static boolean isPlaintext(Buffer buffer) throws EOFException{
            try {
                Buffer prefix = new Buffer();
                long byteCount = buffer.size() < 64 ? buffer.size() : 64;
                buffer.copyTo(prefix, 0, byteCount);
                for (int i = 0; i < 16; i++) {
                    if (prefix.exhausted()) {
                        break;
                    }
                    int codePoint = prefix.readUtf8CodePoint();
                    if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                        return false;
                    }
                }
                return true;

            }catch (EOFException e){
                return false;
            }
        }


        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long t1 = System.nanoTime();  //返回最准确的可用系统计时器的当前值，以毫微秒为单位。
            L.d(tag, "Sending request %s on %s%n%s", request.url(), request.method(),
                    request.headers());
            try{
                if(request.body() != null){
                    if(!request.body().contentType().equals(MediaType.parse("\"multipart/form-data\""))){
                        final Buffer buffer = new Buffer();
                        request.body().writeTo(buffer);
                        if(isPlaintext(buffer)){
                            L.d(tag,buffer.clone().readUtf8());
                        }
                    }
                }
            }catch (Exception ignored){

            }
            Response response = chain.proceed(request);

            long t2 = System.nanoTime();
            L.d(tag, "Received response(%s) for %s in %.1fms%n%s", response.code(),
                    response.request().url(), (t2 - t1) / 1e6d, response.headers());

            try {
                if(response.body() != null){
                    ResponseBody responseBody = response.body();
                    BufferedSource source = responseBody.source();
                    source.request(Long.MAX_VALUE); // // Buffer the entire body.
                    Buffer buffer = source.buffer();
                    if(isPlaintext(buffer)){
                        L.d(tag,buffer.clone().readUtf8());
                    }
                }
            }catch (Exception ignored){
            }
            return response;
        }
    }



    public interface HeaderPlusListener{
        /**
         * http请求拦截
         * @param originalRequest 原始Request
         * @param builder 前面处理后的builder
         * @param parameters 前面向后传递的参数
         * @return {@link Request.Builder}
         */
        Request.Builder headerInterceptor(Request originalRequest, Request.Builder builder,
                                          Map<String, Object> parameters);
    }


    public interface ErrorHandleListener {
        /**
         *
         * @param response {@link Response}
         * @return Response
         * @throws Exception
         */
        Response checkError(Response response) throws Exception;
    }


    public OkHttpClient.Builder cloneClient() {
        if (getClient() == null) {
            throw new IllegalStateException("Not Initialize");
        }
        return getClient().newBuilder();
    }

    public OkHttpClient getClient() {
        if (mClient == null) {
            throw new IllegalStateException("Not Initialize");
        }
        return mClient;
    }

}
